// test_wasm_delaunay.js (跨环境适配版)
// 同时支持Node.js和浏览器环境

// 声明全局变量用于存储JavaScript版本的Delaunay库
let delaunayJS = null;

// 动态加载JavaScript版本的Delaunay库
async function loadDelaunayJS() {
  if (delaunayJS) return delaunayJS;

  try {
    if (typeof window !== 'undefined') {
      // 浏览器环境: 从全局变量加载Delaunay库
      // 注意: HTML中通过script标签加载的库暴露为'Delaunay'而不是'delaunayJS'
      if (window.Delaunay) {
        delaunayJS = window.Delaunay;
        console.log('已从全局变量加载JavaScript版本Delaunay库');
      } else if (window.delaunayJS) {
        delaunayJS = window.delaunayJS;
        console.log('已从全局变量加载JavaScript版本Delaunay库');
      } else {
        console.warn('浏览器环境中未找到全局Delaunay或delaunayJS对象，尝试动态导入');
        // 如果支持动态导入
        // 检查是否支持动态导入
        if (typeof window !== 'undefined' && typeof window.import === 'function') {
          try {
            const module = await import('./libs/delaunay.js');
            delaunayJS = module.default || module;
            console.log('已动态导入JavaScript版本Delaunay库');
          } catch (e) {
            console.error('动态导入失败，尝试从相对路径导入', e);
            try {
              const module = await import('./delaunay.js');
              delaunayJS = module.default || module;
            } catch (e2) {
              console.error('从相对路径导入也失败', e2);
            }
          }
        }
      }
    } else if (typeof require === 'function') {
      // Node.js环境: 使用require导入
      try {
        // 尝试从libs目录导入
        delaunayJS = require('./libs/delaunay.js');
        console.log('已从libs目录加载JavaScript版本Delaunay库');
      } catch (e) {
        console.error('从libs目录加载失败，尝试从当前目录导入', e);
        try {
          delaunayJS = require('./delaunay.js');
          console.log('已从当前目录加载JavaScript版本Delaunay库');
        } catch (e2) {
          console.error('从当前目录导入也失败', e2);
        }
      }
    }
  } catch (error) {
    console.error('加载JavaScript版本Delaunay库失败:', error);
  }

  return delaunayJS;
}

class DelaunayWasm {
  constructor() {
    this.module = null;
    this.useWasm = true; // 默认使用WebAssembly版本
  }

  async loadWasm() {
    try {
      // 根据运行环境加载WebAssembly模块
      let buffer;
      if (typeof window === 'undefined') {
        // Node.js环境
        const { readFile } = await import('fs/promises');
        const { fileURLToPath } = await import('url');
        const { dirname } = await import('path');
        const __filename = fileURLToPath(import.meta.url);
        const __dirname = dirname(__filename);
        buffer = await readFile(`${__dirname}/delaunay.wasm`);
      } else {
        // 浏览器环境
        const response = await fetch('delaunay.wasm');
        buffer = await response.arrayBuffer();
      }

      // 创建WASI导入对象
      const wasiImport = {
        'wasi_snapshot_preview1': {
          // 添加必要的WASI函数
          fd_write: () => 0,
          fd_close: () => 0,
          fd_seek: () => 0,
          fd_read: () => 0,
          environ_sizes_get: () => 0,
          environ_get: () => 0,
          proc_exit: () => {}
        }
      };

      this.module = await WebAssembly.instantiate(buffer, {
        env: {
          abort: () => console.error('Abort called from Wasm'),
          emscripten_notify_memory_growth: () => {}
        },
        ...wasiImport
      });
      console.log('WebAssembly模块加载成功');
      // 打印所有导出函数
      // 打印所有导出函数
      console.log('WebAssembly模块导出函数:', Object.keys(this.module.instance.exports));
      return true;
    } catch (error) {
      console.error('加载WebAssembly模块失败:', error);
      return false;
    }
  }

  // 切换使用WASM还是JS版本
  setUseWasm(useWasm) {
    this.useWasm = useWasm;
    console.log(`已切换到${useWasm ? 'WebAssembly' : 'JavaScript'}版本的三角剖分`);
  }

  // 清理内存缓冲区
  cleanup() {
    if (this.module && this.module.instance && this.module.instance.exports.wasm_free) {
      const exports = this.module.instance.exports;
      if (this.pointsPtr) {
        exports.wasm_free(this.pointsPtr);
        this.pointsPtr = null;
        this.pointsBuffer = null;
      }
      if (this.triangleCountPtr) {
        exports.wasm_free(this.triangleCountPtr);
        this.triangleCountPtr = null;
      }
      console.log('内存缓冲区已清理');
    }
  }

  // 三角剖分函数
  async triangulate(points) {
    if (this.useWasm) {
      return this.triangulateWasm(points);
    } else {
      return await this.triangulateJS(points);
    }
  }

  // WebAssembly版本的三角剖分
  triangulateWasm(points) {
    if (!this.module) {
      console.error('WebAssembly模块尚未加载');
      return null;
    }
    
    try {
      const exports = this.module.instance.exports;
      
      // 检查是否存在必要的函数
      if (!exports.triangulate_points || !exports.wasm_malloc || !exports.wasm_free) {
        throw new Error('未找到必要的WebAssembly函数');
      }
      
      const numPoints = points.length;
      
      // 优化1: 使用Float32Array代替Float64Array减少数据量
      const flatPoints = new Float32Array(numPoints * 2);
      for (let i = 0; i < numPoints; i++) {
        flatPoints[i * 2] = points[i].x;
        flatPoints[i * 2 + 1] = points[i].y;
      }
      
      // 优化2: 复用内存缓冲区
      if (!this.pointsBuffer || this.pointsBuffer.length < flatPoints.length) {
        // 分配内存存储点数据
        const pointsSize = flatPoints.length * 4; // 4 bytes per float
        this.pointsPtr = exports.wasm_malloc(pointsSize);
        if (!this.pointsPtr) {
          throw new Error('内存分配失败 (points)');
        }
        this.pointsBuffer = new Float32Array(exports.memory.buffer, this.pointsPtr, flatPoints.length);
      }
      
      // 复制点数据到WebAssembly内存
      this.pointsBuffer.set(flatPoints);
      
      // 优化3: 复用三角形数量缓冲区
      if (!this.triangleCountPtr) {
        this.triangleCountPtr = exports.wasm_malloc(4); // 4 bytes per int
        if (!this.triangleCountPtr) {
          throw new Error('内存分配失败 (triangle count)');
        }
      }
      
      // 调用三角剖分函数
      const startTime = performance.now();
      const resultPtr = exports.triangulate_points(this.pointsPtr, numPoints, this.triangleCountPtr);
      const endTime = performance.now();
      const duration = endTime - startTime;
      console.log(`WebAssembly三角剖分耗时: ${duration.toFixed(2)}ms`);
      
      // 记录计时数据
      if (typeof window !== 'undefined') {
        // 在全局对象中存储历史计时数据
        if (!window.triangulationTimings) {
          window.triangulationTimings = [];
        }
        window.triangulationTimings.push({
          timestamp: new Date().toISOString(),
          numPoints: numPoints,
          duration: duration
        });
        console.log('三角剖分计时数据已记录，历史记录数:', window.triangulationTimings.length);
      }
      
      // 读取三角形数量
      const triangleCountBuffer = new Int32Array(exports.memory.buffer, this.triangleCountPtr, 1);
      const triangleCount = triangleCountBuffer[0];
      console.log(`三角形数量: ${triangleCount}`);
      
      // 对于大规模点集，建议在不需要结果后清理内存
      // 但为了性能，我们先不释放，而是复用缓冲区
      console.log('内存缓冲区将被复用');
      // 注意：对于非常大的点集，应在适当的时候调用cleanup()方法
      
      if (!resultPtr || triangleCount <= 0) {
        throw new Error(`三角剖分失败，返回空结果或无效的三角形数量: ${triangleCount}`);
      }
      
      // 创建结果数组
      const resultArray = new Int32Array(
        exports.memory.buffer,
        resultPtr, triangleCount * 3
      );
      
      // 复制结果
      const triangles = Array.from(resultArray);
      console.log(`三角剖分结果: ${triangles.length} 个索引 (${triangles.length / 3} 个三角形)`);
      
      // 注意：不要释放resultPtr，因为WebAssembly模块可能在内部管理这个内存
      // 如果需要释放，应该由WebAssembly模块提供相应的函数
      
      return triangles;
    } catch (error) {
      console.error('三角剖分过程中出错:', error);
      return null;
    }
  }

  // JavaScript版本的三角剖分
  async triangulateJS(points) {
    try {
      // 确保已加载JavaScript版本的Delaunay库
      const delaunayJS = await loadDelaunayJS();
      if (!delaunayJS || typeof delaunayJS.triangulate !== 'function') {
        console.error('JavaScript版本Delaunay库未正确加载或不包含triangulate方法');
        return null;
      }

      console.log('使用JavaScript版本进行三角剖分');
      const numPoints = points.length;
      console.log(`点数量: ${numPoints}`);

      // 转换点格式为JS库需要的格式 [[x1,y1], [x2,y2], ...]
      const jsPoints = points.map(point => [point.x, point.y]);

      // 调用JS库的三角剖分函数
      const startTime = performance.now();
      const triangles = delaunayJS.triangulate(jsPoints);
      const endTime = performance.now();
      const duration = endTime - startTime;
      console.log(`JavaScript三角剖分完成，耗时: ${duration.toFixed(2)}ms`);

      // 记录计时数据
      if (typeof window !== 'undefined') {
        if (!window.triangulationTimings) {
          window.triangulationTimings = [];
        }
        window.triangulationTimings.push({
          timestamp: new Date().toISOString(),
          numPoints: numPoints,
          duration: duration,
          type: 'js'
        });
        console.log('JavaScript三角剖分计时数据已记录');
      }

      return triangles;
    } catch (error) {
      console.error('JavaScript三角剖分过程中出错:', error);
      return null;
    }
  }
}

// 创建一个实例并导出
const delaunay = new DelaunayWasm();
export default delaunay;

// 性能测试主函数
async function runPerformanceTest() {
  console.log('开始WebAssembly三角剖分性能测试...');
  
  // 1. 生成50000个随机点
  const numPoints = 50000;
  const points = [];
  for (let i = 0; i < numPoints; i++) {
    points.push({
      x: Math.random() * 1000,  // 随机坐标范围[0, 1000)
      y: Math.random() * 1000
    });
  }
  console.log(`生成随机点集: ${numPoints}个点`);
  
  // 2. 加载WebAssembly模块
  const loadSuccess = await delaunay.loadWasm();
  if (!loadSuccess) {
    console.error('WASM模块加载失败，无法进行测试');
    return;
  }
  
  // 3. 执行三角剖分并测量性能
  console.log('执行WebAssembly三角剖分...');
  const startTime = performance.now();
  const triangles = await delaunay.triangulate(points);
  const endTime = performance.now();
  
  // 4. 输出测试结果
  if (triangles) {
    console.log(`测试结果: 处理${numPoints}个点`);
    console.log(`生成三角形数量: ${triangles.length / 3}`);
    console.log(`WebAssembly三角剖分耗时: ${(endTime - startTime).toFixed(2)}ms`);
  } else {
    console.error('三角剖分执行失败');
  }
  
  // 5. 清理资源
  delaunay.cleanup();
}

// 执行测试
runPerformanceTest().catch(console.error);